package
{
	import away3d.containers.ObjectContainer3D;
	
	import caurina.transitions.Tweener;
	
	import flash.text.TextFormat;
	

	public class Grid
	{
		/**
		 * tableau deux dimensions de Block représentant la grille et ses cases
		 * case à null => un bloc n'est pas présent dans la case
		 */
		private var grille:Array;

		private var nb_largeur:int;

		private var nb_hauteur:int;
		
		private var partie:Tetris3D;

		public function Grid(largeur:int, hauteur:int, partie:Tetris3D)
		{
			this.partie = partie;
			
			nb_largeur = largeur;
			nb_hauteur = hauteur;
			grille = new Array(hauteur);
			// pour chaque ligne
			for (var i:int = 0; i < nb_hauteur; i++) {
				// on parcourt en largeur
				grille[i] = new Array(largeur);
				for (var j:int = 0; j < nb_hauteur; j++) {
					grille[i][j] = null; //false;
				}
			}
		}

		/**
		 * positionne l'équivalent binaire d'un GBlock dans la grille
		 */
		public function positionner(gb:GBlock):void {

			var type:String = gb.getType();
			//trace('positionner '+type+' à ('+x+', '+y+')');

			var temp_x:int = gb.posX;
			var temp_y:int = gb.posY;//+gb.blockHeight-1;

			grille[temp_y][temp_x] = gb.lesBlocks[0];//true;

			var j:int = 0; // compteur de bloc créés
			for (var i:int = 0; i < type.length; i++) {
				var c:String = type.charAt(i).toUpperCase();
				switch (c) {
					case 'L':
						temp_x--;
						break;
					case 'U':
						temp_y--;
						break;
					case 'R':
						temp_x++;
						break;
					case 'D':
						temp_y++;
						break;
				}
				
				if (type.charAt(i) == c) {
					// majsucule : on positionne, le bloc compte
					grille[temp_y][temp_x] = gb.lesBlocks[j+1];//true;		
					j++;
				}
				
			}
			// on change de child
			for each (var bloc:Block in gb.lesBlocks) {
				if (bloc.parent) {
					//bloc.parent.removeChild(bloc);
				}
				
				partie.addChild(bloc);
				
			}
			render();
		}

		/**
		 * indique si on peut déplacer le bloc dans la direction indiquée
		 */
		public function isMovable(gb:GBlock, direction:String):Boolean {
			return canMove(gb, gb.getType(), direction);
		}
		
		/**
		 * indique si oui ou non, le bloc peut etre rotaté
		 */
		public function canRotate(gb:GBlock, newHash:String):Boolean {
			
			return canMove(gb, newHash);
		}
		
		private function canMove(gb:GBlock, hash:String, direction:String = ""):Boolean {
			var type:String = hash;
			
			var temp_x:int = gb.posX;
			var temp_y:int = gb.posY;
			
			var isMovable:Boolean = true;
			
			if (direction != "") {
				switch (direction) {
					case 'L':
						temp_x--;
						break;
					case 'U':
						temp_y--;
						break;
					case 'R':
						temp_x++;
						break;
					case 'D':
						temp_y++;
						break;
				}
			}
			
			if (	temp_y >= nb_hauteur 
				|| 	grille[temp_y][temp_x]
				|| 	temp_x < 0
				|| 	temp_x >= nb_largeur 	) {
				isMovable = false;
			} else {
				for (var i:int = 0; i < type.length; i++) {
					var c:String = type.charAt(i).toUpperCase();
					switch (c) {
						case 'L':
							temp_x--;
							break;
						case 'U':
							temp_y--;
							break;
						case 'R':
							temp_x++;
							break;
						case 'D':
							temp_y++;
							break;
					}
					if (	temp_y >= nb_hauteur 
						|| 	grille[temp_y][temp_x]
						|| 	temp_x < 0
						|| 	temp_x >= nb_largeur	) {
						isMovable = false;
					}
				}
			}
			
			return isMovable;
		}


		/**
		 * vérifie s'il n'y a pas de ligne "gagnante"
		 * i.e dont il n'y a que des blocs sur toute la ligne
		 * @return un tableau avec d'indices des lignes gagnantes et un tableau vide s'il n'y en a aucune
		 * (les indices sont obligatoirement rangés du plus petit au plus grand)
		 */
		private function getWinningLines():Array {
			var result:Array = [];

			// on parcourt la grille
			var indiceLigne:int = 0;
			var isWinning:Boolean;
			var emergency:Boolean = false;
			var isLoose:Boolean = false;
			var i:int;
			for each (var ligne:Array in grille) {
				isWinning = true;
				i = 0;
				while (/*isWinning && */i < nb_largeur) {
					isWinning = isWinning && ligne[i] != null;
					if (indiceLigne <= 8 && ligne[i]) {
						emergency = true;
					}
					if (indiceLigne <= 4 && ligne[i]) {
						isLoose = true;
					}
					i++;
				}
				// on a parcouru toute la ligne, on regarde si c'est toujours bon
				if (isWinning) {
					trace(' ligne gagnante : '+indiceLigne);
					result.push(indiceLigne);
				}
				indiceLigne++;
			}
			
			// lumiere rouge
			Main3D.isEmergency = emergency;
			Main3D.isLoosing = isLoose;

			return result;
		}

		/**
		 * permet de supprimer les lignes "gagnantes" (pleines) s'il y en a 
		 */
		public function deleteWinningLines():void {
			var toDelete:Array = getWinningLines();
			var i:int;
			var bloc:Block;
			
			
			// maj score
			var tf:TextFormat = Main3D.score.getTextFormat();
			Main3D.score.text = (int)(Main3D.score.text) + toDelete.length*10;
			Main3D.score.setTextFormat(tf);
			
			//* BLOC COMMENT
			
			// les indices étant rangés du plus petit au plus grand, on a pas besoin de faire des décalages d'indice ou un tri 
			for each (var numLine:int in toDelete) {
				for (i = 0; i < nb_largeur; i++) {
					bloc = grille[numLine][i];
					
					
					Tweener.addTween(bloc, {
						time:0.8,
						transition:"easeInExpo",
						scaleX:0.01,
						scaleY:0.01,
						scaleZ:0.01,
						rotationX:45,
						rotationY:45,
						rotationZ:-45,
						onComplete: function ():void {
							if (this.parent) {
								this.parent.removeChild(this);						
							}
							//this = null;
						}
					});
					grille[numLine][i] = null;
					
				}
				
				grille.splice(0,0, new Array(nb_largeur)); // on ajoute un ligne en haut
				grille.splice(numLine+1, 1);			   // on supprime la ligne "gagnante"
				
			}
			
			// on va réaffecter les positions aux blocs
			
			
			/*for each (var ligne:Array in grille) {
				for (var j:int = 0; j < nb_largeur; j++) {
					if (ligne[j]) {
						bloc = ligne[j];
						bloc.x = j * Tetris2D.LARGEUR_BLOCK_PX;
						bloc.y = i * Tetris2D.LARGEUR_BLOCK_PX;
					}
				}
				i++;
			}*/
			
			//*/
			
			render(true);
		}


		public function toString():String {
			var result:String = "";
			// pour chaque ligne
			for (var i:int = 0; i < nb_hauteur; i++) {
				// on parcourt en largeur
				for (var j:int = 0; j < nb_largeur; j++) {
					result += (grille[i][j] ? "[ ]" : "   " )+"";
				}
				result += "|\n";
			}

			return result;
		}
		
		/**
		 * permet de disposer les blocs de façon cohérente
		 */
		public function render(tweener:Boolean = false):void {
			var i:int;
			var bloc:Block;
			i = 0;
			for each (var ligne:Array in grille) {
				for (var j:int = 0; j < nb_largeur; j++) {
					if (ligne[j]) {
						bloc = ligne[j];
						if (tweener) {
							Tweener.addTween(bloc, {
								delay:0.4,
								time:0.8,
								transition:"easeOutBounce",
								x : j * Tetris3D.LARGEUR_BLOCK_PX,
								y : i * Tetris3D.LARGEUR_BLOCK_PX
							});							
						} else {
							bloc.x = j * Tetris3D.LARGEUR_BLOCK_PX;
							bloc.y = i * Tetris3D.LARGEUR_BLOCK_PX;
						}
						bloc.z = 0;
						
					}
				}
				i++;
			}
		}
	}
}